#!/usr/bin/env python

import re
import os
import string
import sys
import xml.etree.ElementTree as ET
import subprocess


#extern "C" int extra(int in, int *out) {
#    static int (*__extra)(int, int *) = NULL;
#
#    if (__extra == NULL) {
#        __extra = (int (*)(int, int *))dlsym(RTLD_NEXT, "extra");
#        if (NULL == __extra) {
#            fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
#        }
#    }
#
#    tditrace("@T+extra()");
#    int ret = __extra(in, out);
#    tditrace("@T-extra()");
#
#    return ret;
#}


def get_type(root, type_id, pointer=""):

    for PointerType in root.iter('PointerType'):
        if (PointerType.attrib["id"] == type_id):

            #print "PointerType.id : %s"%PointerType.attrib["id"]
            #print "PointerType.type : %s"%PointerType.attrib["type"]

            return get_type(root, PointerType.attrib["type"], " * ") + pointer


    for FundamentalType in root.iter('FundamentalType'):
        if (FundamentalType.attrib["id"] == type_id):
            #print "FundamentalType : %s"%FundamentalType.attrib["name"]
            return FundamentalType.attrib["name"] + pointer;

    for Typedef in root.iter('Typedef'):
        if (Typedef.attrib["id"] == type_id):
            #print "Typedef : %s"%Typedef.attrib["name"]
            return Typedef.attrib["name"] + pointer;

    for Enumeration in root.iter('Enumeration'):
        if (Enumeration.attrib["id"] == type_id):
            #print "Enumeration : %s"%Enumeration.attrib["name"]
            return Enumeration.attrib["name"] + pointer;

    for CvQualifiedType in root.iter('CvQualifiedType'):
        if (CvQualifiedType.attrib["id"] == type_id):
            #print "CvQualifiedType : %s"%CvQualifiedType.attrib["type"]

            for FundamentalType in root.iter('FundamentalType'):
                if (FundamentalType.attrib["id"] == CvQualifiedType.attrib["type"]):
                    #print "CvQualifiedType FundamentalType : %s"%FundamentalType.attrib["name"]
                    return 'const ' + FundamentalType.attrib["name"] + pointer

            for Typedef in root.iter('Typedef'):
                if (Typedef.attrib["id"] == CvQualifiedType.attrib["type"]):
                    #print "CvQualifiedType Typedef : %s"%Typedef.attrib["name"]
                    return 'const ' + Typedef.attrib["name"] + pointer

            for PointerType in root.iter('PointerType'):
                if (PointerType.attrib["id"] == CvQualifiedType.attrib["type"]):

                    #print "PointerType.id : %s"%PointerType.attrib["id"]
                    #print "PointerType.type : %s"%PointerType.attrib["type"]

                    return get_type(root, PointerType.attrib["type"], " * ") + pointer



    print "ERROR in " + type_id


def parse_xml(input_xml):


    tree = ET.parse(input_xml)

    root = tree.getroot()

    prog = re.compile(sys.argv[2])

    for Function in root.iter('Function'):

        function_name = Function.attrib["name"]

        if (prog.match(function_name)):

            #print "Function : %s"%Function.attrib["name"]

            argument_names = []
            argument_types = []
            ellipsis = False

            return_type = get_type(root, Function.attrib["returns"])

            i = 1;
            for Arguments in Function.iter('Argument'):
                if "name" in Arguments.attrib:
                    argument_names.append(Arguments.attrib["name"])
                else:
                    argument_names.append('arg' + str(i))
                    i+= 1
                argument_types.append(get_type(root, Arguments.attrib["type"]))

            if Function.find('Ellipsis') is not None:
                ellipsis = True

            #print '----'
            #print function_name
            #print return_type
            #print argument_names
            #print argument_types
            #print '----'

            #extern "C" int extra(int in, int *out) {
            #    static int (*__extra)(int, int *) = NULL;
            #
            #    if (__extra == NULL) {
            #        __extra = (int (*)(int, int *))dlsym(RTLD_NEXT, "extra");
            #        if (__extra == NULL) {
            #            fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
            #        }
            #    }
            #
            #    tditrace("@T+extra()");
            #    int ret = __extra(in, out);
            #    tditrace("@T-extra()");
            #
            #    return ret;
            #}

            print '\nextern \"C\" %s %s'%(return_type, function_name),

            if not argument_types and not ellipsis:
                print '(void)'
            else:
                print '(',
                if argument_types:
                    for index in range(len(argument_names)):
                        if (index > 0):
                            print ', ',
                        print argument_types[index] + ' ' + argument_names[index],
                
                if ellipsis:
                    print ', ...',
                print ')'

            print '{'

            if not argument_types:
                print '   static ' + return_type + ' (* __' + function_name + ') (void) = NULL;'
            else:
                print '   static ' + return_type + ' (* __' + function_name + ')',
                print '(',
                for index in range(len(argument_names)):
                    if (index > 0):
                        print ', ',
                    print argument_types[index],
                print ') = NULL;'

            print '   if (__' +  function_name + ' == NULL) {'

            print '      __' + function_name + ' = (' + return_type + ' (*)',
            if not argument_types:
                print '(void))',
            else:
                print '(',
                for index in range(len(argument_names)):
                    if (index > 0):
                        print ', ',
                    print argument_types[index],
                print '))',

            print 'dlsym(RTLD_NEXT, \"' + function_name + '\");'
            print '      if (__' +  function_name + ' == NULL) {'
            print '         fprintf(stderr, \"Error in dlsym: %s(%s)\\n\", dlerror()?dlerror():"?",\"' + function_name + '\");'
            print '      }'
            print '   }'


            print '   tditrace("@A+' + function_name + '()\");'

            if return_type == 'void':
                print '   __' + function_name,
            else:
                print '   ' + return_type + ' ret = ' + '__' + function_name,

            if not argument_types:
                print '();'
            else:
                print '(',
                for index in range(len(argument_names)):
                    if (index > 0):
                        print ', ',
                    print argument_names[index],
                print ');'


            #    int ret = __extra(in, out);
            #    tditrace("@T-extra()");
            #
            print '   tditrace("@A-' + function_name + '()\");'

            if return_type != 'void':
                print '   return ret;'
            print '}'


def main():

    if len(sys.argv) >= 3:

        parse_xml(sys.argv[1])

    else:

        print("Usage: %s xmlfile functionpattern" % sys.argv[0])

if __name__ == "__main__":
        main()
